home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / programm.ing / ams__l~1.zoo / src / ca_pack.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-05  |  4.7 KB  |  176 lines

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  This file is part of the Atari Machine Specific Library,
  4. //  and is Copyright 1992 by Warwick W. Allison.
  5. //
  6. //  You are free to copy and modify these sources, provided you acknowledge
  7. //  the origin by retaining this notice, and adhere to the conditions
  8. //  described in the file COPYING.
  9. //
  10. //////////////////////////////////////////////////////////////////////////////
  11.  
  12. /**********************************************************\
  13.  *                                                        *
  14.  *  CrackArt file compressor.                             *
  15.  *   by Warwick Allison, May 8th 1992.                    *
  16.  *                                                        *
  17.  *  Reverse engineered from compressor routine:           *
  18.  *                                                        *
  19.  * ; CRACK ART Kompressionsroutine für Bilddaten (CA?)    *
  20.  * ; Copyright © Detlef Röttger 04.03.1990                *
  21.  *                                                        *
  22.  *  The full file format (in bytes) is:                   *
  23.  *       'C', 'A', 1, Rez, Colours x 2, Data              *
  24.  *                                                        *
  25.  *  Compressions Codes:                                   *
  26.  *   Esc Esc          = One Esc byte                      *
  27.  *   Esc 2 0          = Delta to end                      *
  28.  *   Esc 2 Hi Lo      = HiLo+1 repeated Deltas (HiLo>255) *
  29.  *   Esc 1 Hi Lo byte = HiLo+1 repeated bytes (HiLo>255)  *
  30.  *   Esc 0 Esc byte   = Esc+1 repeated byte               *
  31.  *   Esc Count byte   = Count+1 repeated byte (Count>2)   *
  32.  *   Byte             = Literal byte                      *
  33.  *                                                        *
  34. \**********************************************************/
  35.  
  36. #include "ca_pack.h"
  37. #include <values.h>
  38.  
  39.  
  40. const unsigned char Zero=0;
  41. const unsigned char One=1;
  42. const unsigned char Two=2;
  43.  
  44. int Compress(unsigned char Esc,unsigned char Delta,short Offset,unsigned char* From,int nel,FILE *f)
  45. // f=0 implies dry run.  Returns size of output.
  46. {
  47.     int Size=0;
  48.  
  49.     int basei=0;
  50.     int i=basei;
  51.     int count=nel;
  52.     while (count) {
  53.         unsigned char b=From[i];
  54.         int newi=i,newbasei=basei;
  55.         for (int N=0; N<count && From[newi]==b; N++) {
  56.             newi+=Offset;
  57.             if (newi>=nel) {
  58.                 newbasei++;
  59.                 newi=newbasei;
  60.             }
  61.         }
  62.  
  63.         if (N==count && b==Delta) {
  64.             // Dumb, hacky compression special-case in CrackArt
  65.             if (f) {
  66.                 fwrite(&Esc,sizeof(unsigned char),1,f);
  67.                 fwrite(&Two,sizeof(unsigned char),1,f);
  68.                 fwrite(&Zero,sizeof(unsigned char),1,f);
  69.             }
  70.             Size+=3;
  71.             count=0;
  72.         } else {
  73.             if (N>3) {
  74.                 i=newi;
  75.                 basei=newbasei;
  76.                 if (N<=256) {
  77.                     unsigned char n=N-1;
  78.                     if (f) fwrite(&Esc,sizeof(unsigned char),1,f);
  79.                     if (n==Esc) {
  80.                         Size++;
  81.                         if (f) fwrite(&Zero,sizeof(unsigned char),1,f);
  82.                     }
  83.                     if (f) {
  84.                         fwrite(&n,sizeof(unsigned char),1,f);
  85.                         fwrite(&b,sizeof(unsigned char),1,f);
  86.                     }
  87.                     Size+=3;
  88.                     count-=N;
  89.                 } else {
  90.                     if (N>65536) N=65536;
  91.                     unsigned short n=N-1;
  92.  
  93.                     if (f) fwrite(&Esc,sizeof(unsigned char),1,f);
  94.                     if (b==Delta) {
  95.                         if (f) {
  96.                             fwrite(&Two,sizeof(unsigned char),1,f);
  97.                             fwrite(&n,sizeof(unsigned short),1,f);
  98.                         }
  99.                     } else {
  100.                         if (f) {
  101.                             fwrite(&One,sizeof(unsigned char),1,f);
  102.                             fwrite(&n,sizeof(unsigned short),1,f);
  103.                             fwrite(&b,sizeof(unsigned char),1,f);
  104.                         }
  105.                         Size++;
  106.                     }
  107.                     Size+=4;
  108.                     count-=N;
  109.                 }
  110.             } else {
  111.                 if (b==Esc) {
  112.                     if (f) fwrite(&Esc,sizeof(unsigned char),1,f);
  113.                     Size++;
  114.                 }
  115.                 if (f) fwrite(&b,sizeof(unsigned char),1,f);
  116.                 Size++;
  117.                 i+=Offset;
  118.                 if (i>=nel) {
  119.                     basei++;
  120.                     i=basei;
  121.                 }
  122.                 count--;
  123.             }
  124.         }
  125.     }
  126.  
  127.     return Size;
  128. }
  129.  
  130. short GoodOffset[]={160,80,320,8,4,640,2,1,480,0}; // 0 terminated.
  131.  
  132. void SaveCrackArtData(unsigned char* From, int nel, FILE* f, int Compression)
  133. {
  134.     int Freq[256];
  135.     unsigned char Esc;
  136.     unsigned char Delta;
  137.     int MinF=MAXINT;
  138.     int MaxF=MININT;
  139.     int i;
  140.  
  141.     for (i=0; i<256; i++) Freq[i]=0;
  142.  
  143.     for (i=0; i<nel; i++) Freq[From[i]]++;
  144.  
  145.     for (i=0; i<256; i++) {
  146.         if (Freq[i]<=MinF) {  // "<=" rather than "<" to act like CrackArt
  147.             MinF=Freq[i];
  148.             Esc=i;
  149.         }
  150.         if (Freq[i]>MaxF) {
  151.             MaxF=Freq[i];
  152.             Delta=i;
  153.         }
  154.     }
  155.  
  156.     int MinSize=MAXINT;
  157.     short Offset=GoodOffset[0];
  158.  
  159.     // Only testing one is pointless (might as well just use it).
  160.     if (Compression) Compression++;
  161.  
  162.     for (i=0; i<Compression && GoodOffset[i]; i++) {
  163.         int Size=Compress(Esc,Delta,GoodOffset[i],From,nel,0);
  164.         if (Size<MinSize) {
  165.             MinSize=Size;
  166.             Offset=GoodOffset[i];
  167.         }
  168.     }
  169.  
  170.     fwrite(&Esc,sizeof(Esc),1,f);
  171.     fwrite(&Delta,sizeof(Delta),1,f);
  172.     fwrite(&Offset,sizeof(Offset),1,f);
  173.  
  174.     Compress(Esc,Delta,Offset,From,nel,f);
  175. }
  176.